/**
 * This is a public module that contains the code needed to initialize the library
 */
package time;
import haxe.macro.Context;
import haxe.macro.MacroTools;
#if macro

import time.providers.Provider;
import haxe.macro.Expr;
#end

class Startup 
{
	@:macro public static function init() : Expr
	{
		//TODO use sourcePath from provider to be faster
		var all:Array<{ p:Provider, vars:Array<String>, aliases:Array<String> }> = [];
		
		var providers:Hash<Provider> = untyped Provider.providers;
		for (_var in providers.keys())
		{
			var p = providers.get(_var);
			
			var found = false;
			for (a in all)
			{
				if (a.p == p)
				{
					a.vars.push(_var);
					found = true;
				}
			}
			
			if (!found)
			{
				all.push({p:p, vars:[_var], aliases:[]});
			}
		}
		/* TODO add support for alias on the runtime
		var aliases:Hash<Provider> = untyped Provider.aliases;
		for (alias in aliases.keys())
		{
			var p = aliases.get(alias);
			
			var found = false;
			for (a in all)
			{
				if (a.p == p)
				{
					a.aliases.push(alias);
					found = true;
				}
			}
			
			if (!found)
			{
				all.push({p:p, vars:[], aliases:[alias]});
			}
		}
		*/
		var bl = [];
		var pos = Context.currentPos();
		var mk = MacroTools.mk;
		
		function concat(arr:Array<String>, e)
		{
			return switch (arr.length)
			{
				case 0: mk(EConst(CIdent("null")), pos);
				case 1: mk(EBinop(OpAssign, MacroTools.path(arr[0].split("."), pos), e), pos);
				default: 
					var cur = arr.pop();
					mk(EBinop(OpAssign, MacroTools.path(arr[0].split("."), pos), concat(arr,e)), pos);
			}
		}
		
		for (a in all)
		{
			bl.push(concat(a.vars.copy(), 
			 	mk(ECall(MacroTools.path(["haxe","Unserializer","run"], pos), [
					mk(EConst(CString( haxe.Serializer.run( a.p ) )), pos)
				]), pos)
			));
		}
		
		return mk(EBlock(bl), pos);
	}
	
}